import { getScrollBarSize } from "@/utils/dom"
import { CSSProperties, MouseEventHandler, UIEventHandler, useCallback, useEffect, useRef, useState } from "react"
import styled from "styled-components"
import { getRect } from "./utils/calcBox"
import { Rect } from "./types"
import { cellDeault, initDefaultCellOption } from "./config"
import Exl, { ExcelInterface, InputCellInfo } from "./utils/main"
import { Button } from "antd"
import { eq } from "lodash"

// 初始化单元格默认配置
initDefaultCellOption()
// 获取滚动条宽度
const sbSize = getScrollBarSize()

function ExcelRect() {
  const [canvasDom, setCanvasDom] = useState<HTMLCanvasElement | null>(null)
  const maskWrapperRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  const [excel, setExcel] = useState<ExcelInterface>()
  const [chooseCellStyle, setChooseCellStyle] = useState<CSSProperties & { ow: number; oh: number }>({ ow: 0, oh: 0 })
  const [inputStyle, setInputStyle] = useState<CSSProperties>()
  // 点击的第一个单元格
  const [inputCell, setInputCell] = useState<InputCellInfo | null>()

  // 初始化渲染
  useEffect(() => {
    if (canvasDom) {
      // 获取canvas的大小位置信息
      const rect = getRect(canvasDom) as Rect
      const ec = Exl(canvasDom, rect)
      ec.render()
      setExcel(ec)
    }
  }, [canvasDom])

  // 鼠标点击状态
  const clickedState = useRef(false)
  // 点击单元格事件
  const mouseDone = useCallback<MouseEventHandler<HTMLDivElement>>((ev) => {
    clickedState.current = true
    setInputStyle({ left: -10000, top: -10000 })
    if (excel) {
      const { scrollLeft, scrollTop } = maskWrapperRef.current as HTMLDivElement
      // 点击位置 + 滚动距离 - dom位置
      const x = ev.clientX + scrollLeft - excel.rect.left
      const y = ev.clientY + scrollTop - excel.rect.top
      const sc = excel.getCellStart({ x, y })
      // 显示动态单元格
      if (sc) {
        const obj = {
          left: sc.x - scrollLeft,
          top: sc.y - scrollTop,
          width: cellDeault.width,
          height: cellDeault.height,
          ow: sc.x,
          oh: sc.y
        }
        setChooseCellStyle(old => eq(old, obj) ? old : obj)
      }
    }
  }, [excel])
  const mouseMove = useCallback<MouseEventHandler<HTMLDivElement>>((ev) => {
    if (excel && clickedState.current) {
      const { scrollLeft, scrollTop } = maskWrapperRef.current as HTMLDivElement
      // 点击位置 + 滚动距离 - dom位置
      const x = ev.clientX + scrollLeft - excel.rect.left
      const y = ev.clientY + scrollTop - excel.rect.top
      const { mixCell: smc, endCellPosition } = excel.getCellEnd({ x, y })
      if (smc && endCellPosition) {
        const width = smc.ex - smc.x
        const height = smc.ey - smc.y
        const style: CSSProperties & { ow: number; oh: number } = {
          left: smc.x - scrollLeft,
          top: smc.y - scrollTop,
          width,
          height,
          ow: smc.x,
          oh: smc.y
        }
        const endCellPositionArr = endCellPosition.split("-")
        type BorderWidth = "borderTopWidth" | "borderBottomWidth" | "borderLeftWidth" | "borderRightWidth"
        style[`border${endCellPositionArr[0]}Width` as BorderWidth] = width - cellDeault.width
        style[`border${endCellPositionArr[1]}Width` as BorderWidth] = height - cellDeault.height
        setChooseCellStyle(style)
      }
    }
  }, [excel])
  const mouseUp = useCallback<MouseEventHandler<HTMLDivElement>>((ev) => {
    clickedState.current = false
  }, [])
  // 滚动重绘canvas事件
  const maskScroll = useCallback<UIEventHandler<HTMLDivElement>>((x) => {
    if (excel) {
      const { scrollLeft, scrollTop } = (x.target as HTMLDivElement)
      excel.transform(scrollLeft, scrollTop).render()
      setChooseCellStyle(old => {
        old.left = old.ow - scrollLeft
        old.top = old.oh - scrollTop
        return { ...old }
      })
    }
  }, [excel])

  const [w, setW] = useState(1600)
  const [h, setH] = useState(1200)

  // 点击滚动事件
  const clickScroll = useCallback((dir) => {
    const { scrollHorizontalBtnStep, scrollVerticalBtnStep } = cellDeault
    const maskDom = maskWrapperRef.current
    if (maskDom) {
      switch (dir) {
        case "up":
          maskDom.scrollTo({ behavior: "smooth", top: maskDom.scrollTop - scrollVerticalBtnStep })
          break;
        case "down":
          if (maskDom.scrollTop + 600 + sbSize === maskDom.scrollHeight) {
            setH(old => old + scrollVerticalBtnStep)
            setTimeout(() => {
              maskDom.scrollTo({ behavior: "smooth", top: maskDom.scrollHeight })
            }, 50);
          } else
            maskDom.scrollTo({ behavior: "smooth", top: maskDom.scrollTop + scrollVerticalBtnStep })
          break;
        case "left":
          maskDom.scrollTo({ behavior: "smooth", left: maskDom.scrollLeft - scrollHorizontalBtnStep })
          break;
        case "right":
          if (maskDom.scrollLeft + 800 + sbSize === maskDom.scrollWidth) {
            setW(old => old + scrollHorizontalBtnStep)
            setTimeout(() => {
              maskDom.scrollTo({ behavior: "smooth", left: maskDom.scrollWidth })
            }, 50);
          } else
            maskDom.scrollTo({ behavior: "smooth", left: maskDom.scrollLeft + scrollHorizontalBtnStep })
          break;
        default:
          break;
      }
    }
  }, [])

  // 双击输入
  const dbClickInput = useCallback<MouseEventHandler<HTMLDivElement>>((ev) => {
    const { scrollLeft, scrollTop } = ev.target as HTMLDivElement
    if (excel) {
      const dom = inputRef.current
      const x = ev.clientX + scrollLeft - excel.rect.left
      const y = ev.clientY + scrollTop - excel.rect.top
      const sc = excel.getCellStart({ x, y })
      if (sc && dom) {
        setInputCell(old => old && old.x === sc.x && old.y === sc.y ? old : sc)
        setInputStyle({
          left: sc.x - scrollLeft,
          top: sc.y - scrollTop
        })
        dom.focus()
      }
    }
  }, [excel])

  const renderText = useCallback(() => {
    const dom = inputRef.current
    if (dom && excel && inputCell) {
      const text = dom.value
      dom.value = ""
      excel.renderSingleCellText(inputCell.info.xi, inputCell.info.yi, text)
    }
  }, [excel, inputCell])

  return (
    <>
      <Button onClick={() => clickScroll("up")}>上</Button>
      <Button onClick={() => clickScroll("down")}>下</Button>
      <Button onClick={() => clickScroll("left")}>左</Button>
      <Button onClick={() => clickScroll("right")}>右</Button>
      <Container>
        <ChooseMask style={chooseCellStyle} />
        <Input ref={inputRef} style={inputStyle} onBlur={renderText} />
        <FunctionalMaskWrapper ref={maskWrapperRef} onScroll={maskScroll}>
          <FunctionalMask w={w} h={h} onDoubleClick={dbClickInput} onMouseDown={mouseDone} onMouseMove={mouseMove} onMouseUp={mouseUp} />
        </FunctionalMaskWrapper>
        <Canvas ref={setCanvasDom} />
      </Container>
    </>
  )
}

export default ExcelRect;

const Container = styled.div`
  width: ${800 + sbSize}px;
  height: ${600 + sbSize}px;
  overflow: hidden;
  margin-left: 10px;
  margin-top: 10px;
  position: relative;
  /* *::-webkit-scrollbar {
    width : 10px;
    height: 10px;
    cursor: pointer;
  }
  *::-webkit-scrollbar-thumb {
    border-radius: 10px;
    box-shadow   : inset 0 0 5px rgba(0, 0, 0, 0.2);
    background   : #535353;
  }
  *::-webkit-scrollbar-track {
    box-shadow   : inset 0 0 5px rgba(0, 0, 0, 0.2);
    border-radius: 10px;
    background   : #ededed;
  }
  *::-webkit-scrollbar-button {
    width: 10px;
    height: 10px;
    &:hover {
      background: green;
    }
  } */
`

const ChooseMask = styled.div`
  left: -10000px;
  top: -10000px;
  width: 0;
  height: 0;
  position: absolute;
  background: hsla(0,0%,100%,.1);
  border: 0 solid rgba(31,187,125,.1);
  z-index: 100;
  outline: #1fbb7d solid 2px;
`

const Input = styled.input`
  position: absolute;
  left: -10000px;
  top: -10000px;
  width: ${cellDeault.width}px;
  height: ${cellDeault.height}px;
  z-index: 400;
  border: none;
  outline: none;
`

const FunctionalMaskWrapper = styled.div`
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  right: ${sbSize}px;
  bottom: ${sbSize}px;
  z-index: 300;
  background-color: rgba(230,230,230,0.2);
  cursor: cell;
  overflow: auto;
  overflow: overlay;
`

const FunctionalMask = styled.div<{ w: number; h: number }>`
  width: ${({ w }) => w}px;
  height: ${({ h }) => h}px;
`

const Canvas = styled.canvas`
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  right: ${sbSize}px;
  bottom: ${sbSize}px;
`
